This file documents all the changes made to SpriteWorld since version 2.0 was released. Many things were changed that will affect you as a user. If you were previously using a version of SpriteWorld prior to version 2.2, it is important that you read through all the changes that have been made since the version you are using was released, and make changes to your source code where necessary. You will only have to do this once, and then will be able to take advantage of the new features in the current version. You should also print out the new versions of the documentation. (Inside SpriteWorld, SpriteWorld - Scrolling, SpriteWorld - Tiling, etc.)
Changes in 2.2.1
• Modified SWCollideSpriteLayer and SWCollideCircularSpriteLayer so it is now safe to call SWRemoveSpriteFromAnimation (but not SWRemoveSprite) to remove as many Sprites as you want from any SpriteLayer from within your collideProc. Note that it is still unsafe to do this from a MoveProc or FrameProc. For those routines, it is only safe to remove the srcSpriteP that is passed to that function, or Sprites from Layers other than the one the srcSpriteP is in. But your collideProc may remove any Sprite(s) it wishes without any problems.
• Fixed a bug where SWCreateRegionFromGWorldAndRect wouldn't work correctly. This bug wouldn't have affected you unless you called this function directly, or called BlitPixie8BitFlipSprite on a Sprite with a maskRgn.
SpriteWorld 2.2.1 is a minor update to 2.2. The flexibility that was added to SWCollideSpriteLayer was considered important enough to warrant this update, even though little else has changed since 2.2.
Changes in 2.2
Tiling Changes:
• IMPORTANT! The name of the function SWSetTileMaskDrawProc was changed to SWSetPartialMaskDrawProc. However, if you forget to change your code, you won't get any compiler errors, because a new function called SWSetTileMaskDrawProc was added. This function is different from the old SWSetTileMaskDrawProc, so it is important that you change the name! To help ensure that you remember to do so, the new SWSetTileMaskDrawProc function will return an error code if you try to install either BlitPixie8BitPartialMaskDrawProc or BP8BitInterlacedPartialMaskDrawProc as its DrawProc, since this function is now for normal mask DrawProcs, not partialMask drawProcs. But you have to check for an error code for this to be of any help! I recommend doing a Find & Replace through all your source code to change all occurrences of SWSetTileMaskDrawProc to SWSetPartialMaskDrawProc.
• Added two functions to allow you to use multiple tile layers (where all layers are the same size and scroll the same speed): SWSetNumActiveTileLayers, and SWSetSpriteLayerUnderTileLayer.
• Added several new functions for adding a picture or pattern behind your tiles: SWCreateExtraBackFrame, SWDisposeExtraBackFrame, SWSetPortToExtraBackFrame.
• SWInstallTileMap, SWDrawTile, SWReturnTileUnderPixel, and SWCheckSpriteWithTiles have all had tileLayer parameters added to them, so they know which tile layer you are operating on.
• SWSetSpriteUnderTiles has been removed, since its functionality has been replaced by SWSetSpriteLayerUnderTileLayer.
• Due to the changes necessary to allow you to use multiple tile layers, if you previously accessed the spriteWorldP->tileMapStructP variable, you must now use spriteWorldP->tileLayerArray[tileLayer] instead, where tileLayer is a number between 0 and 9 specifying the tile layer of the TileMap you wish to read.
SpriteLayer Changes:
• SWRemoveSprite, SWSwapSprite, SWInsertSpriteBeforeSprite, and SWInsertSpriteAfterSprite have all had their spriteLayer parameters removed. This is because each Sprite now keeps track of the layer it is currently in. In addition, SWSwapSprite now return an error code if the Sprites being swapped are not both in the same layer, SWRemoveSprite returns an error code if the Sprite isn't part of any layer, and SWAddSprite, SWInsertSpriteBeforeSprite, and SWInsertSpriteAfterSprite return error codes if the Sprite is already part of a Layer.
Misc Changes:
• Totally rebuilt the circular scrolling engine to do what I previously thought impossible - it now allows you to make the offscreen area smaller than your "virtual" circular world, provided that the virtual world's width and height are evenly divisible by your offscreen area's width and height. Many of the limitations it had before are now gone.
• Modified SWMarkSpriteForRemoval so it now moves the Sprite into a special layer in the SpriteWorld designated just for Sprites that need to be erased and removed. This means that the Sprites are removed immediately as far as your program is concerned, and the name of the function was changed back to SWRemoveSpriteFromAnimation to indicate this. You now no longer need to check each Sprite's spriteRemoval field to see if it has been marked for removal, since you will no longer encounter any Sprites that need removing after you remove it with SWRemoveSpriteFromAnimation.
HOWEVER, there is a new limitation imposed by this system; if you are removing a Sprite while in a MoveProc, FrameProc, or CollideProc, the Sprite must either be the source Sprite that was passed to that function, or it must be a Sprite in a different Layer as the source Sprite. In the case of a CollideProc, you may remove both Sprites only if they are in separate Layers. Otherwise, you may only remove one of the Sprites from within the CollideProc. In other words, SWRemoveSpriteFromAnimation has the same requirements as SWRemoveSprite. It just does the cleanup for you.
• The names of the SWGameUtils.c functions HideMenuBar and ShowMenuBar were changed to SWHideMenuBar and SWShowMenuBar, so they don't conflict with the System 8.5 functions of the same name. Additionally, it was discovered that since SWShowMenuBar disposes of the region returned to you when you call SWHideMenuBar, you should *not* dispose this region as was previously instructed. It will be disposed for you by SWShowMenuBar. If you dispose it yourself, it could cause a crash when SWShowMenuBar attempts to dispose it.
• Sped up the scaling blitters by pre-computing the scaling info and reusing it for each line. While this sped everything up by a small amount, it also allowed me to make more dramatic optimizations for the following operations:
- Direct-to-screen scaling.
- Clipped scaled sprites.
- Shrunk sprites.
• It is now highly recommended that you check the value returned by SWStickyError just before starting your animation, and also during the animation. This will help you catch error codes that you don't check for, such as the error codes returned by the various SWSetDrawProc functions. All of the demos now check SWStickyError.
• It is also recommended that you make use of the new SWSetCleanUpSpriteWorld function, documented in Inside SpriteWorld. This will ensure that if an assertion failure or FatalError() gets triggered and you had previously called SWSyncSpriteWorldToVBL with a value of true, the VBL task will be removed before the error causes your program to quit, ensuring that the machine doesn't lock up. Previously the computer would lock up if an error occurred after the SpriteWorld had been set to sync to the VBL.
• Moved Sounds.c and Sounds.h from Shark Attack into the SpriteWorld Sources -> Utils folder, and renamed them SWSounds.c and SWSounds.h. They are now "official" SpriteWorld Util files. They are intended to be simple and easy to use. Docs are in the Documentation -> Add-On Docs folder. Also cleaned up the package to make it more user-friendly and added a few new features, like volume and stereo location control. Shark Attack now plays its sounds in stereo!
• Removed the PartialMaskDrawProcs in BlitPixieScaled.c and BlitPixieRotated.c, since they were the same as the standard scaled or rotated MaskDrawProcs. If you previously used one of those PartialMaskDrawProcs, you should switch over to the equivalent scaled MaskDrawProc.
• SWDisposeFrame, SWDisposeWindowFrame, SWDisposeSprite, SWDisposeSpriteLayer, and SWDisposeSpriteWorld now require the address of the pointer you pass to them (not just the pointer itself), so they can set it to NULL. This means that SWDisposeFrame(theFrameP) needs to be changed to SWDisposeFrame(&theFrame), SWDisposeSprite(theSpriteP) becomes SWDisposeSprite(&theSpriteP), etc.
• Modified SWIsPointInSprite so it will not detect that the point is in the Sprite if the point.v is equal to the Sprite's destFrameRect.bottom or the point.h is equal to the Sprite's destFrameRect.right. Previously, a collision would be detected if this were the case, which is incorrect, since the bottom and right side of the Sprite's destFrameRect (or any Rect for that matter) are actually one pixel outside of the actual Sprite image.
• It was discovered that Brian's Translucency blitters do not mix with idle Sprites. Unfortunately, there is no way to fix this problem internally. This means that if you use translucency, you should install a MoveProc or FrameProc that is called every frame and sets the Sprite's needsToBeDrawn flag to true.
• Added tileLayer parameters to the GetTileBrightnessLevel and SetTileBrightnessLevel functions in Brian's Utils' SWTinting.c.
• SWSetCurrentFrame now returns an error code if the specified Frame is not part of the Sprite.
• Greatly improved the accuracy of the FPS report of all the demos.
• Think C projects are no longer supported, since I no longer have a 68k Mac to test them on. (Think C crashes on PowerMacs.) All projects should run except Shark Attack. To get Shark Attack's Think C project to compile, remove Sounds.c and add SWSounds.c.
New Functions:
• Added SWChangeTileSize, which allows you to change the size of your tiles without having to call SWExitTiling and SWInitTiling, which would dispose of all of your tiles. Could be useful for things such as switching between a map screen and your game screen, where the map screen uses a different size of tile than the game screen.
• Added several new functions to SWFastLine.c for drawing and copying lines and framed rects in both scrolling and non-scrolling worlds. Also changed the function previously named SWDrawLine to SWDrawLine68kAsm. See the Add-On Docs folder for more information.
• Added assertions to SpriteWorld. Now if you forget to do something important (such as locking the SpriteWorld before running the animation), you will most likely get a dialog box reporting the problem instead of having the program crash (Good idea, no? :-), provided you have the required ALRT and DITL resources. You can, of course, turn assertions off for the final build of your program if you wish, since it may run slightly faster, and since your final build should be free of the bugs that would cause assertion failures. See the section covering Assertions in Inside SpriteWorld for more information. (Just do a search for "Assertions" to find it.)
• Added SWPauseSpriteLayer and SWUnpauseSpriteLayer.
• Added SWDisposeAllSpritesInLayer (both removes and disposes the Sprites).
• Added SWCountNumSpritesInLayer.
• Added SWCloneSpriteFromTile. (Docs are in Inside SpriteWorld.)
Bug Fixes:
• Fixed several nasty bugs in Brian's BlitPixieScaled.c file:
1) Fixed a problem where the BlitPixieScaledRectDrawProcs would not draw the image properly if it were shrunk vertically.
2) Fixed a problem with all the scaling DrawProcs where they would not only draw the image incorrectly if it were clipped, but also usually crash. Since this problem has been fixed, Brian's scaling blitters may now be used in a scrolling SpriteWorld without any problems.
3) Fixed the problem of random artifacts around the right and bottom sides of a scaled Sprite.
4) Fixed a bug where SWSetSpriteScaledSize would have no effect if the Sprite had only one frame.
Some of the scaling DrawProc names have changed. However, this shouldn't affect you as a user, since SWSetSpriteScaledSize sets the DrawProc for you automatically. If you previously used any of the DrawProc names directly, look at the beginning of BlitPixieScaled.c for the new names.
• Fixed a bug in SWTranslucentBlitters.c where a crash could occur when a 16-bit Sprite was clipped. In addition, SWDispose16BitTranslucencyTable now works properly, and SWCreate16BitTranslucencyTable now returns an error code. Make sure to check the error code if you use this function.
• Fixed a bug in SWUpdateFrameMasks where the region mask would sometimes not get updated properly.
• Fixed SWDrawTile so it now changes the tileMap even if the row and column of the tile that was changed is not visible in the current visScrollRect.
• Improved the logic in SWCheckSpriteWithTiles so that it now detects collisions with tiles that your Sprite may have previous "jumped" over if it was moving so fast that it went completely over a tile in a single frame. It now doesn't matter how fast your sprite moves; even if it's going 500 pixels per frame, any tile (even a small one, such as 10x10) will still be detected if the Sprite moves over it. Also improved the search so that when the fixPosition parameter is true, the first tile checked is the one just in front of the sprite's current position, not the one it's sitting on. So if the right side of your sprite is on column 25, and your tiles are 50x50, and you move the sprite to the right and check for tiles with kSWRightSide as your searchType, the first tile checked will be column 1 (pixel column 50), not tile 0 (the one the right side was already in.)
Changes in 2.1.1
SpriteWorld 2.1.1 was a maintenance release that fixed an important bug in the scrolling routines where a NULL pointer was used and could potentially cause a crash.
Changes in 2.1
Tiling changes:
- The TileMap is now created as a single large block, instead of a bunch of tiny blocks (one for each row), and this is now done using Handles instead of Pointers. This has many benefits. The main one is that SWSaveTileMap and SWLoadTileMap require less memory, and the chances of SWSaveTileMap failing for lack of memory is much smaller than it had been previously. The only reason it might fail now is because A) The disk is full, or B) There isn't enough room to load the old TMAP resource that is going to be replaced with the one you're saving (since it must be loaded before RemoveResource can be called to remove it). If the latter of these is the case, your program can simply call UniqueID to save the TileMap using an unused resource ID, so that it can simply be saved, without having to first load and dispose any old TMAP resources with the same ID. This means that you should always be able to save your TileMap, unless the disk gets full.
- The Tiling routines for working with a TileMap are now "separated" from SpriteWorld a bit more. SWCreateTileMap and SWLoadTileMap now only return a TileMapStructPtr to the caller; they don't install the TileMap in the SpriteWorld. You must now do this yourself with SWInstallTileMap. This allows much more freedom when working with TileMaps, since you can load as many TileMaps at a time as you want, and easily switch between them with SWInstallTileMap. Note that existing programs that use the Tiling routines will not work until you add a call to SWInstallTileMap after loading or creating it. See any of the demos that use Tiling for an example of how to use SWInstallTileMap.
Also, since the number of rows and columns can no longer be stored in the SpriteWorld, but must be stored in the TileMap itself (since there may be more than one TileMap loaded at a time), a new structure was created, called the TileMapStruct, that contains the pointer to the TileMap array as well as the number of rows and columns in the TileMap. It also contains Handles to the TileMap as well as other information that is used internally by SpriteWorld. This means that you must now pass a TileMapStructPtr to the TileMap functions, instead of passing a TileMapPtr. Also, to access the TileMap, you must now use myTileMapStructP->tileMap[x][y], instead of myTileMap[x][x]. See the documentation for SWCreateTileMap for more information.
- Fixed a problem where the heap could get corrupted if SWDrawTile or SWChangeTileImage were called too many times in a single frame of the animation.
- Idle sprites are now properly redrawn in a non-scrolling animation when overwritten by a tile that changed images.
- Fixed a bug where a portion of an invisible idle sprite could get drawn if the sprite overlapped a tile that had changed images.
- Fixed a problem in SWLoadTileFromCicnResource that could cause the tile to not be drawn correctly if the tile size set with SWInitTiling wasn't a standard CICN size (8X8, 16X16, 32X32, 64X64, etc.) and CopyBits was used. For instance, if the tile size was set to 29X29 and a 32X32 CICN was loaded, the entire 32X32 image may have been scaled to fit inside the 24X24 square when drawn, if CopyBits were used to draw it.
Other changes to SpriteWorld:
- The name of the function SWRemoveSpriteFromAnimation was changed to SWMarkSpriteForRemoval in order to make the name more clearly indicate the true actions of the function, since it doesn't remove the sprite immediately, but marks it to be removed after it has been erased.
- In order to make the SpriteWorld library callable from Pascal, SW_FUNC is now declared as pascal (see SWCommonHeaders.h). The only way this will affect you is that all functions that are called from within SpriteWorld, such as your custom MoveProcs, FrameProcs, CollideProcs, ScrollingWorldMoveProcs, and TileChangeProcs, must now have their function prototypes prefixed with "SW_FUNC". (See any of the demos for an example.)
- SWCreateSpriteWorldFromWindow now requires an additional parameter. Called "maxDepth", this parameter can be used to force SpriteWorld to create its offscreen GWorlds at a depth lower than the current monitor depth. If zero is passed the offscreen GWorlds are made the same depth as the monitor, as before.
- Added a borderWidth parameter to SWCreateSpriteFromSinglePict. Now you're no longer forced to place a 1-pixel border between sprite frames that use this function!
- Added a borderHeight parameter to SWCreateSpriteFromSinglePictXY, so you're no longer forced to use a 1-pixel border between horizontal rows.
- All of the functions that create multiple frames from a single pict (SWCreateSpriteFromSinglePict, SWCreateSpriteFromSinglePictXY, and SWLoadTilesFromPict) are now much faster when creating frames that use region masks. Using kPixelMask is still the fastest method, but the method of creating multiple region masks from a single pict is now faster than it had been.
- SWUpdateScrollingSpriteWorld now calls the SpriteWorld's scrollingWorldMoveProc, if there is one, so that the visScrollRect is correctly positioned before the animation is copied to the screen.
- Fixed the spelling of the frameHasOccured variable of the SpriteWorldRec. It is now spelled frameHasOccurred.
- Modified SWMoveSprite to only move the sprite if the new position is different from the old position, thus avoiding unnecessary redraws if the sprite is moved to the same location it was at previously.
- SWBounceSprite and SWWrapSprite now return a Boolean value indicating whether they bounced/wrapped the sprite. The functions have also been optimized a little bit, so they may be slightly faster than they were previously.
- SWSetScrollingWorldMoveBounds now makes sure the visScrollRect is still within the new moveBounds.
- Changed the name of the GetScreenDepth function in SWGameUtils.c to GetGDeviceDepth to more accurately describe its function. Also added GetDepthFromGlobalRect to SWGameUtils.c.
- Fixed a bug in the scrolling engine where pieces of idle sprites were getting erased as you scrolled around. In addition, I improved the idle sprite code. Previously, the entire idle sprite was getting redrawn each frame as it scrolled into view. Now only the tiny sliver that has just scrolled into view gets redrawn.
- SWPixelCollision now checks to make sure the srcSpriteP is an 8-bit sprite, and if it is not, the function returns 0 (false). It's up to you to check the depth before calling this function, and to use an alternate routine such as SWRegionCollision if you're not in 8-bit.
- Added a userData variable to the Frame structure. Now you can easily store custom information about each individual frame of a sprite. Just put a pointer here to your custom record, and you can store more than a long's worth of data.
- SWInstallTileMap no longer checks to make sure the tileMapStructP passed to the function is not NULL. This is so you can use this function to set the current tileMap to NULL if you've disposed it with SWDisposeTileMap. This also means SWInstallTileMap no longer returns an error code.
- Several other minor internal changes and fixes.
New functions:
- A whole package for doing scaling, rotating, translucency, and lighting effects have been added, and are available in the SpriteWorld Files->Utils->Brian's Extensions folder. There you will find complete source code as well as documentation for the routines.
- A bunch of routines for handling split-screen scrolling and circular scrolling have been added. See the file "Multi-Screen Scrolling" in the "Add-On Docs" folder of your Documentation folder for more info.
- Added SWWindowMoved. If you're using direct-to-screen blitting, calling this routine whenever the user drags a window will allow direct-to-screen blitting to be used with movable windows.
- Added SWSetPostEraseCallBack and SWSetPostDrawCallBack. These allow you to provide a callback function to be called from SWAnimate after it erases and draws the sprites.
- Added SWChangeWorldRect, which allows you to change the size and location of a SpriteWorld's worldRect without having to dispose and recreate the SpriteWorld.
- Added SWFastAnimateScrollingSpriteWorld which updates only the portions of a scrolling animation that have changed since the previous frame. Note that I do *not* recommend this for use by a game, since the scrolling will dramatically slow down when you start scrolling, and suddenly speed up when you stop. However, this function is great for level editors, since you can quickly update the screen after the user changes a tile.
- SWFlagRectAsChanged lets you tell SpriteWorld when you have changed something in the background frame of the SpriteWorld. Simply call SWFlagRectAsChanged, passing a rect containing the area that you changed, and SpriteWorld will automatically copy that rectangle to the work area and to the screen during the next call to SWAnimate, and will also redraw any idle sprites that were erased by that rectangle when it was copied to the work area.
- SWCheckSpriteWithTiles allows you to quickly and easily determine if a Sprite has come in contact with any Tile in a specified set of Tiles. It also has an option to move the sprite off the tile it ran into, which is great for sprites that run into walls.
- SWReturnTileUnderPixel returns the tileID of the tile under pixelCol and pixelRow. You could do this pretty easily yourself, but this function makes it slightly more convenient.
- SWSetSpriteFrameAdvanceMode allows you to change the automatic frame advancement mode, so that when a sprite's frame index is advanced in SWProcessSpriteWorld and the frames of a sprite reach the last or first frame, the frame advancement either wraps around, or changes direction and goes the other way. Previously SpriteWorld always wrapped them around, so that when advancing past the last frame of the sprite, the first frame would be the next one to be drawn. Now you can tell SpriteWorld to simply change the direction of the frame advancement when it reaches the last or first frame, instead of wrapping around. Although this could have been accomplished by creating a FrameProc to handle this, it is slightly more efficient if SpriteWorld handles it itself.
- SWCopyFrame lets you duplicate a Frame.
- SWUpdateFrameMasks allows you to modify a Frame's image, and then update the masks for that Frame to match the Frame image.
- SWFastCloneSprite provides a slightly faster alternative to SWCloneSprite, but has several side-effects. Read the documentation in Inside SpriteWorld for more info.
- SWSetFrameHotSpot allows you to specify the hotSpot for each Frame of a Sprite. This can be particularly useful when you have a Frame that changes sizes, and you need a way to tell SpriteWorld how the Frame should be positioned relative to the previous Frame.
- SWSetTransparentColor lets you load self-masking sprites which use a color other than white as their transparent color. See the documentation for this function in Inside SpriteWorld for the details.
- RestoreSystemPalette has been added to GameUtils.c. Few of the files in the "Utils" folder are documented, so look at the source code to get a brief description of each function.
New Demos:
- Added Shark Attack, which demonstrates how to use SpriteWorld in an actual game. This program demonstrates things such as how to add and remove sprites from an animation on the fly, how to perform collision detection, and in general, how to set things up properly for a game.
- Added a Split-Screen Scrolling demo, accompanied by brand-new routines for doing split-screen scrolling. (Actually, you can have more than two screens - you can have as many as you want!)
- Various other demos are included in the SpriteWorld 2.1 Extra Demos package, available from wherever you downloaded SpriteWorld.
Changes to the distribution package:
- Updated all source code to be compatible with the latest version of the Universal Headers that come with CodeWarrior Pro and are also available via Apple's web site. This means that the source code is no longer compatible with earlier versions of the Universal Headers. You can either update to the latest headers, or modify the SpriteWorld source files so they are compatible with the older headers again. For more information, read the "About These Demos" file in the SpriteWorld Examples folder. Also see this document for information about getting the PPC demos to run with CodeWarrior Pro.
- All warnings generated when compiling a project with CodeWarrior have been fixed!
- A new package containing additional demos for SpriteWorld was created, called "SpriteWorld 2.1 Demos", so it will show up next to SpriteWorld 2.1 when listed in libraries like InfoMac. It is recommended that you download this package as well - it contains addition demos, such as the Large Background Scrolling, the source code to the Wrapping Illustration, and three new demos by Brian Roddy that demonstrate his utilities for lighting, translucency, scaling, and rotating. You're welcome to contribute your own demos too; if you have something you think other users might want to see, send it to me (Vern), and I'll consider adding it to the package.
- Many additions to the SpriteWorld FAQ and SpriteWorld Tips and Tricks files.
- Cleaned up the code for the Simple demo. Although at first glance it may seem to be more complex, I believe that when you take a closer look, you'll find that it is much easier to read and understand, as well as a much better example of how you should set up your own projects. I figured that if people were basing their own games on this demo, it had better be a proper demonstration of how to set up and run an animation!
- All of the PPC applications except for SpriteTest were removed to cut down on the size of the SpriteWorld package. You can easily make your own PPC demos by compiling the PPC CodeWarrior projects.
- All CodeWarrior projects were updated to CW 10 format so they can be opened by CW Pro.
- Removed all SpriteWorld Library files, since it seems every other release of CodeWarrior changes the library file format. Simply include the SpriteWorld source files directly instead of using libraries in your project. This also enables you to step through the SpriteWorld source code when debugging.
- All projects now require Scrolling.c to be added to the project, regardless of whether your application makes use of the scrolling routines or not. This is because the new SWChangeWorldRect function calls routines in Scrolling.c.
- Greatly improved the error reporting of the SpriteWorld demos that use SWApplication.c. It now not only gives you the error code, but also the file name and line number where the error occurred! If you use the error reporting code in SWApplication.c in your own projects, you'll need to copy the new ALRT, DITL, and STR# resources number 128 from one of the demos that use SWApplication.c into your project for the new error reporting code to work correctly.